﻿#include <bits/stdc++.h>
using namespace std;
using namespace std::filesystem;
// 当前选中的数据库
string current_db;

// ========== 文件操作函数 ==========
void create_database(string db)
{
    if (!exists(db))
    {
        create_directory(db);
        printf("Database '%s' created.\n", db.c_str());
    }
    else
        fprintf(stderr, "Database '%s' has existed.\n", db.c_str());
}
void drop_database(string db)
{
    if (exists(db))
    {
        remove_all(db);
        printf("Database '%s' deleted.\n", db.c_str());
    }
    else
        fprintf(stderr, "Database '%s' not exist.\n", db.c_str());
}
void use_database(string db)
{
    if (exists(db))
    {
        current_db = db;
        printf("Using database '%s'.\n", db.c_str());
    }
    else
        fprintf(stderr, "Database '%s' not exist.\n", db.c_str());
}

// ========== 表结构存储 ==========
void create_table(string table, vector<pair<string, string>> columns)
{
    if (current_db.empty())
    {
        fprintf(stderr, "No database selected.\n");
        return;
    }
    path metap = path(current_db) / (table + ".meta");
    path datap = path(current_db) / (table + ".data");
    if (exists(metap) || exists(datap))
    {
        fprintf(stderr, "Table '%s' already exists.\n", table.c_str());
        return;
    }

    ofstream meta(metap);
    for (auto i : columns)
        meta << i.first << " " << i.second << endl;
    meta.close();

    ofstream data(datap);
    data.close();

    printf("Table '%s' created.\n", table.c_str());
}
void drop_table(string table)
{
    if (current_db.empty())
    {
        fprintf(stderr, "No database selected.\n");
        return;
    }
    bool meta_deleted = remove(path(current_db) / (table + ".meta"));
    bool data_deleted = remove(path(current_db) / (table + ".data"));
    if (meta_deleted && data_deleted)
        printf("Table '%s' deleted\n", table.c_str());
    else
        fprintf(stderr, "Delete failed. Missing files '%s'\n", table.c_str());
}
void info_table(string table)
{
    string s;
    if (current_db.empty())
    {
        fprintf(stderr, "No database selected.\n");
        return;
    }

    path metap = path(current_db) / (table + ".meta");
    if (!exists(metap))
    {
        fprintf(stderr, "Table '%s' not exist.\n", table.c_str());
        return;
    }
    ifstream meta(metap);
    printf("meta:\n");
    while (getline(meta, s))
        cout << s << endl;

    path datap = path(current_db) / (table + ".data");
    if (!exists(datap))
    {
        fprintf(stderr, "Table '%s' not exist.\n", table.c_str());
        return;
    }
    ifstream data(datap);
    printf("data:\n");
    while (getline(data, s))
        cout << s << endl;
}
void insert_table(string table, vector<pair<string, string>> values)
{
    if (current_db.empty())
    {
        fprintf(stderr, "No database selected.\n");
        return;
    }
    vector<pair<string, string>> columns;
    path metap = path(current_db) / (table + ".meta");
    if (!exists(metap))
    {
        fprintf(stderr, "Table '%s' not exist.\n", table.c_str());
        return;
    }
    ifstream meta(metap);
    string s;
    while (getline(meta, s))
    {
        stringstream ss(s);
        string type, name;
        if (ss >> type >> name)
            columns.emplace_back(type, name);
    }
    meta.close();
    int n = values.size(), m = columns.size();
    if (n != m)
    {
        fprintf(stderr, "Error format\n");
        return;
    }
    for (int i = 0; i < n; ++i)
        if (values[i].first != columns[i].second)
        {
            fprintf(stderr, "Error format\n");
            return;
        }
    path datap = path(current_db) / (table + ".data");
    if (!exists(datap))
    {
        fprintf(stderr, "Table '%s' not exist.\n", table.c_str());
        return;
    }
    ofstream data(datap, ios::app);
    for (auto [type, value] : values)
        data << value << ",";
    data << endl;
    data.close();
    printf("Insert successful\n");
}
bool cmp2(string op, double a, double b)
{
    if (op == "==")
        return a == b;
    else if (op == "!=")
        return a != b;
    else if (op == "<")
        return a < b;
    else if (op == "<=")
        return a <= b;
    else if (op == ">")
        return a > b;
    else if (op == ">=")
        return a >= b;
    else
        exit(1141514);
}
bool cmp1(string op, string a, string b)
{
    if (a[0] != '\'')
        return cmp2(op, stod(a), stod(b));
    if (op == "==")
        return a == b;
    else if (op == "!=")
        return a != b;
    else if (op == "<")
        return a < b;
    else if (op == "<=")
        return a <= b;
    else if (op == ">")
        return a > b;
    else if (op == ">=")
        return a >= b;
    else
        exit(1141514);
}
void delete_table(string table)
{
    if (current_db.empty())
    {
        fprintf(stderr, "No database selected.\n");
        return;
    }
    path metap = path(current_db) / (table + ".meta");
    path datap = path(current_db) / (table + ".data");
    if (!exists(metap) || !exists(datap))
    {
        fprintf(stderr, "Table '%s' not exist.\n", table.c_str());
        return;
    }
    remove(datap);
    ofstream data(datap);
    data.close();
    printf("Delete records of %s\n", table.c_str());
}
void delete_table(string table, string type, string op, string value)
{
    if (current_db.empty())
    {
        fprintf(stderr, "No database selected.\n");
        return;
    }
    vector<pair<string, string>> columns;
    path metap = path(current_db) / (table + ".meta");
    if (!exists(metap))
    {
        fprintf(stderr, "Table '%s' not exist.\n", table.c_str());
        return;
    }
    ifstream meta(metap);
    string line;
    while (getline(meta, line))
    {
        stringstream ss(line);
        string type, name;
        if (ss >> type >> name)
            columns.emplace_back(type, name);
    }
    meta.close();
    path datap = path(current_db) / (table + ".data");
    path tempp = path(current_db) / "temp.data";
    ifstream data(datap);
    ofstream temp(tempp);
    string record;
    while (getline(data, record))
    {
        stringstream ss(record);
        int cnt = 0;
        while (getline(ss, line, ',') && type != columns[cnt].second)
            ++cnt;
        if (!cmp1(op, line, value))
            temp << record << endl;
    }
    data.close();
    temp.close();
    remove(datap);
    rename(tempp, datap);
}

void select_table(string table, vector<string> names, string condition, string name, string op2)
{
    // cout<<"?";
    // cout<<endl<<":"<<name<<endl;
    size_t pos = condition.find_first_of("=<>!");
    if (pos == string::npos)
    {
        fprintf(stderr, "Error format\n");
        return;
    }
    string type = condition.substr(0, pos);
    string op = condition.substr(pos, 1);
    if (pos + 1 < condition.size() && condition[pos + 1] == '=')
        op += "=", ++pos;
    string value = condition.substr(pos + 1);
    // cout<<type<<' '<<op<<' '<<value<<endl;
    if (current_db.empty())
    {
        fprintf(stderr, "No database selected.\n");
        return;
    }
    vector<pair<string, string>> columns;
    path metap = path(current_db) / (table + ".meta");
    if (!exists(metap))
    {
        fprintf(stderr, "Table '%s' not exist.\n", table.c_str());
        return;
    }
    ifstream meta(metap);
    string line;
    while (getline(meta, line))
    {
        stringstream ss(line);
        string type, name;
        if (ss >> type >> name)
            columns.emplace_back(type, name);
    }
    meta.close();
    int n = columns.size(), idx;
    if (!name.empty())
        for (int i = 0; i < n; ++i)
            if (columns[i].second == name)
            {
                idx = i;
                break;
            }
    // cout<<"IDX:"<<idx<<endl;
    path datap = path(current_db) / (table + ".data");
    ifstream data(datap);
    vector<vector<string>> vec;
    string record;
    while (getline(data, record))
    {
        stringstream ss(record);
        int cnt = 0;
        while (getline(ss, line, ',') && type != columns[cnt].second)
            ++cnt;
        if (cmp1(op, line, value))
        {
            // cout<<line<<op<<value<<endl;
            stringstream tmp(record);
            vector<string> rec;
            while (getline(tmp, line, ','))
                rec.emplace_back(line);
            vec.emplace_back(rec);
        }
    }
    if (!name.empty())
        sort(vec.begin(), vec.end(), [&](vector<string> &a, vector<string> &b)
             {
        if (op2 == "asc") return cmp1("<", a[idx], b[idx]);
        else return cmp1(">", a[idx], b[idx]); });
    bool f = 0;
    if (names[0] == "*")
        f = 1;
    set<string> se;
    if (!f)
        for (auto i : names)
            se.emplace(i);
    for (auto rec : vec)
    {
        for (int i = 0; i < n; ++i)
            if (f || se.count(columns[i].second))
            {
                cout << rec[i] << " ";
            }
        cout << endl;
    }
    data.close();
}
// ========== 命令解析器 ==========
void execute_sql(const string &sql)
{
    stringstream ss(sql);
    string command, s, type, name, db, table, col_def, into, set, pairstr, from, where, condition, order, by;
    ss >> command;
    if (command == "create")
    {
        ss >> type;
        if (type == "database")
        {
            ss >> db;
            create_database(db);
        }
        else if (type == "table")
        {
            ss >> table;
            vector<pair<string, string>> columns;
            while (getline(ss, col_def, ','))
            {
                col_def.erase(remove(col_def.begin(), col_def.end(), '('), col_def.end());
                col_def.erase(remove(col_def.begin(), col_def.end(), ')'), col_def.end());
                stringstream cs(col_def);
                string type, name;
                cs >> type >> name;
                columns.emplace_back(type, name);
            }
            create_table(table, columns);
        }
    }
    else if (command == "drop")
    {
        ss >> type;
        if (type == "database")
        {
            ss >> db;
            drop_database(db);
        }
        else if (type == "table")
        {
            ss >> table;
            drop_table(table);
        }
    }
    else if (command == "use")
    {
        ss >> db;
        use_database(db);
    }
    else if (command == "info")
    {
        ss >> table;
        info_table(table);
    }
    else if (command == "insert")
    {
        vector<pair<string, string>> values;
        ss >> into >> table >> set;
        if (into != "into" || set != "set")
        {
            fprintf(stderr, "Error format\n");
            return;
        }
        while (getline(ss, pairstr, ','))
        {
            pairstr.erase(remove_if(pairstr.begin(), pairstr.end(), ::isspace), pairstr.end());
            if (pairstr.empty())
                continue;
            size_t pos = pairstr.find('=');
            if (pos == string::npos)
            {
                cout << pairstr << endl;
                fprintf(stderr, "Error format\n");
                return;
            }
            string type = pairstr.substr(0, pos);
            string value = pairstr.substr(pos + 1);
            values.emplace_back(type, value);
            // cout<<type<<' '<<value<<endl;
        }
        if (!values.empty())
            insert_table(table, values);
    }
    else if (command == "delete")
    {
        ss >> from >> table >> where;
        if (where.empty())
        {
            delete_table(table);
            return;
        }
        if (from != "from" || where != "where")
        {
            fprintf(stderr, "Error format\n");
            return;
        }
        getline(ss, condition, ';');
        size_t pos = condition.find_first_of("=<>!");
        if (pos == string::npos)
        {
            fprintf(stderr, "Error format\n");
            return;
        }
        string type = condition.substr(1, pos - 1);
        string op = condition.substr(pos, 1);
        if (pos + 1 < condition.size() && condition[pos + 1] == '=')
            op += "=", ++pos;
        string value = condition.substr(pos + 1);
        delete_table(table, type, op, value);
    }
    else if (command == "select")
    {
        getline(ss, s);
        for (int i = 0; i < (int)s.length(); ++i)
            if (s[i] == ',')
                s[i] = ' ';
        stringstream css(s);
        vector<string> names;
        while (css >> s)
        {
            if (s == "from")
                break;
            names.emplace_back(s);
        }
        css >> table >> where >> condition >> order >> by >> name >> s;
        select_table(table, names, condition, name, s);
    }
}
int main()
{
    string input;
    cout << "运行成功,退出请输入exit;\n";
    while (getline(cin, input, ';'))
    {
        input.erase(0, input.find_first_not_of(" \t\n\r"));
        input.erase(input.find_last_not_of(" \t\n\r") + 1);
        if (input == "exit" || input == "exit;")
            break;
        execute_sql(input);
    }
    return 0;
}